#pragma once

#include <cstring>
#include "basic_config.hpp"
#include "types.hpp"

namespace zuck
{
	template<typename CharType>
	class _CharTraits {
	public:
		using value_type = CharType;
		using int_type   = zuck::size_t;
	public:
		static void reverse(CharType* begin, const CharType* end)
		{
			auto _Tmp = end - 1;
			for (; begin < _Tmp; ++begin, --_Tmp) {
				*begin ^= *_Tmp ^= *begin ^= *_Tmp;
			}
		}

		[[nodiscard]] static zuck::size_t length(const CharType* data)
		{
			zuck::size_t ret = 0;
			for (; *data; ++ret, ++data);

			return ret;
		}

		[[nodiscard]] static zuck::size_t strlen(const char* const String)
		{
			return std::strlen(String);
		}

		//     pattern string          match string
		[[nodiscard]] static zuck::size_t find_first_of
		(const CharType* const src, const CharType* const t, zuck::size_t off = 0)
		{
			int code[256] = { 0 };// ASCII character
			int n{ 0 };
			for (int i = 0; t[i]; ++i, ++n) {
				code[t[i]] |= (1 << i);
			}
			int p{ 0 };
			auto const len = length(src);
			for (zuck::size_t i = off; i < len; ++i) {
				p = (p << 1 | 1) & code[src[i]];
				if (p & (1 << (n - 1))) {
					return i - n + 1;
				}
			}
			return static_cast<zuck::size_t>(-1);
		}

		[[nodiscard]] static zuck::size_t find_last_of
		(const CharType* const str, const CharType* const des, zuck::size_t off = zuck::max_env_size)
		{
			auto const _Srcsize = length(str);
			auto const _Dessize = length(des);
			off = !(off ^ zuck::max_env_size) ? _Srcsize - 1 : off;
			auto _Res = zuck::max_env_size;
			for (; off > 0 && off < _Srcsize; off -= _Dessize) {
				if ((_Res = find_first_of(str, des, off)) != zuck::max_env_size) {
					return _Res;
				}
			}
			return _Res;
		}

		[[nodiscard]] static int compare(const CharType* data1, const CharType* data2)
		{
			for (; *data1 && *(data1 == *data2); ++data1, ++data2);
			int ans = (*data1 - *data2);

			if (ans > 0) {
			// data1 > data2
				return 1;
			}
			else if (ans < 0) {
			// data1 > data2
				return -1;
			}
			// data1 == data2
			return 0;
		}
	};

	using char_traits  = _CharTraits<char>;
	using wchar_traits = _CharTraits<wchar_t>;
	using utf16_traits = _CharTraits<char16_t>;
	using utf32_traits = _CharTraits<char32_t>;
#if __cplusplus__ > 201703L
	using utf8_traits = _CharTraits<char8_t>;
#endif
}

